"""
hlog.py  – 方案 B：多模块独立 logger / 独立文件，不重复打印
用法：
    from hlog import HLog
    log1 = HLog(name="trade")
    log2 = HLog(name="quote", console=False)   # 关闭控制台
    log1.info("hello %s", "trade")
"""
import os
import logging
import logging.handlers
import queue
from atexit import register
from typing import Optional, List


DEFAULT_LEVEL      = logging.INFO
DEFAULT_FMT        = "[%(asctime)s] %(levelname)-5s [%(threadName)s] %(filename)s:%(lineno)d | %(message)s"
DEFAULT_MAX_BYTES  = 50 * 1024 * 1024    # 50 MB
DEFAULT_BACKUP_CNT = 5
DEFAULT_DIR        = "logs"


class HLog:
    """独立 logger 实例，各写各文件，控制台可开关，绝不重复打印"""
    _instances: dict[str, "HLog"] = {}          # 记录已构造的实例（可选缓存）

    def __new__(cls, *, name: str = "root", **kw):
        # 相同 name 复用实例（可选），不同 name 各自独立
        if name not in cls._instances:
            cls._instances[name] = super().__new__(cls)
        return cls._instances[name]

    def __init__(
        self,
        *,
        name: str = "root",
        log_dir: str = DEFAULT_DIR,
        level: int = DEFAULT_LEVEL,
        fmt: str = DEFAULT_FMT,
        max_bytes: int = DEFAULT_MAX_BYTES,
        backup_cnt: int = DEFAULT_BACKUP_CNT,
        console: bool = True,
    ):
        # 防止 __init__ 被多次调用重复加 handler
        if hasattr(self, "_inited"):
            return
        self._inited = True
        self.name = name
        self._build_logger(name, log_dir, level, fmt, max_bytes, backup_cnt, console)

    # ---------- 内部构造 ----------
    def _build_logger(
        self, name: str, log_dir: str, level: int, fmt: str,
        max_bytes: int, backup_cnt: int, console: bool
    ) -> None:
        os.makedirs(log_dir, exist_ok=True)
        formatter = logging.Formatter(fmt, datefmt="%Y-%m-%d %H:%M:%S")

        handlers: List[logging.Handler] = []

        # 1. 文件回卷
        file_path = os.path.join(log_dir, f"{name}.log")
        rf_handler = logging.handlers.RotatingFileHandler(
            file_path, maxBytes=max_bytes, backupCount=backup_cnt, encoding="utf-8"
        )
        rf_handler.setFormatter(formatter)
        handlers.append(rf_handler)

        # 2. 控制台（可选）
        if console:
            sh = logging.StreamHandler()
            sh.setFormatter(formatter)
            handlers.append(sh)

        # 3. 队列 + 监听器
        self.queue: queue.Queue = queue.Queue(-1)
        self.listener = logging.handlers.QueueListener(
            self.queue, *handlers, respect_handler_level=True
        )
        self.listener.start()

        # 4. 取得 logger 并清空旧 handler（关键）
        self.logger = logging.getLogger(name)
        self.logger.handlers.clear()
        self.logger.setLevel(level)
        self.logger.addHandler(logging.handlers.QueueHandler(self.queue))

        # 5. 优雅退出
        register(self.listener.stop)

    # ---------- 代理方法（带 stacklevel 指向业务代码） ----------
    def debug(self, msg: str, *args, **kw):
        self.logger.debug(msg, *args, **kw, stacklevel=2)

    def info(self, msg: str, *args, **kw):
        self.logger.info(msg, *args, **kw, stacklevel=2)

    def warning(self, msg: str, *args, **kw):
        self.logger.warning(msg, *args, **kw, stacklevel=2)

    def error(self, msg: str, *args, **kw):
        self.logger.error(msg, *args, **kw, stacklevel=2)

    def exception(self, msg: str, *args, **kw):
        kw.setdefault("exc_info", True)
        self.logger.error(msg, *args, **kw, stacklevel=2)

    def critical(self, msg: str, *args, **kw):
        self.logger.critical(msg, *args, **kw, stacklevel=2)


# 预置一个默认实例，兼容旧接口（懒加载，避免导入时创建 root.log）
class _LazyLogger:
    def __init__(self):
        self._inst: Optional[HLog] = None
    def _ensure(self) -> HLog:
        if self._inst is None:
            self._inst = HLog(name="root")
        return self._inst
    def __getattr__(self, item):
        return getattr(self._ensure(), item)

logger = _LazyLogger()